//
//  ObjectUtils.swift
//  novelReader
//
//  Created by Ink on 2019/9/12.
//  Copyright © 2019 ChineseAll. All rights reserved.
//

import RxSwift

public func getZMKey(_ suffix: String? = nil,
                     prefix: String? = nil,
                     file: String = #file,
                     function:String = #function,
                     line: Int = #line) -> String {
    return [suffix,file,function,"\(line)",prefix].compactMap({ $0 }).joined(separator: "_")
}

extension ObjectIdentifier: Hashable {}

public protocol IdentifiableObject: AnyObject {
    var objectIdentifier: ObjectIdentifier { get }
}

extension IdentifiableObject {
    public var objectIdentifier: ObjectIdentifier { ObjectIdentifier(self) }
}

// MARK: - ClassNameProtocol
/// 获取类名<字符串>
public protocol ClassNameProtocol {
    
    /// className eg: CustomObject.className = 'CustomObject'
    static var className : String { get }
    
    var className : String { get }
}

extension ClassNameProtocol where Self: NSObjectProtocol  {
    
    public static var className : String {
        NSStringFromClass(self).description.components(separatedBy: ".").last ?? NSStringFromClass(self)
    }
    
    public var className : String {
        String(describing: type(of: self)).description.components(separatedBy: ".").last ?? String(describing: type(of: self))
    }
}

// MARK: - ReuseIdProtocol
/// 注册ReuseId<字符串>
public protocol ReuseIdProtocol: ClassNameProtocol{
    
    /// reuseIdentifier equal className
    static var reuseIdentifier : String { get }
}

extension ReuseIdProtocol {
    
     public static var reuseIdentifier : String { className }
}

extension NSObject : ReuseIdProtocol {}

private extension NSObject.AssociatedKeys {
    static var DisposeBag = getZMKey()
}

// MARK: -  rxDisposeBag
extension NSObject {
    public var rxDisposeBag: DisposeBag {
        get {
            if let disposeBag = mUtilMap[AssociatedKeys.DisposeBag] as? DisposeBag {
                return disposeBag
            }
            else {
                self.rxDisposeBag = DisposeBag()
                return self.rxDisposeBag
            }
        }
        set { mUtilMap[AssociatedKeys.DisposeBag] =  newValue }
    }
}

// MARK: - Weak
public class Weak<T: AnyObject> {
    public weak var value : T?
    public init(value v: T?) {
        value = v
    }
}

// MARK: - 添加拓展 Dictionary
extension NSObject {
    
    fileprivate struct AssociatedKeys {
        static var MUtilMap = malloc(1)
        static var MUtilWeakMap = malloc(1)
    }
    
    public var mUtilMap: NSMutableDictionary {
        get {
            guard let value = objc_getAssociatedObject(self, &AssociatedKeys.MUtilMap) as? NSMutableDictionary else {
                let tMap = NSMutableDictionary()
                self.mUtilMap = tMap
                return tMap
            }
            return value
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.MUtilMap, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        }
    }
    
    public subscript(mUtil key: Any) -> Any? {
        get { mUtilGetValue(key) }
        set { mUtilSetValue(newValue, forKey: key) }
    }
    
    public func mUtilGetValue(_ key: NSDictionary.Key) -> Any? {
        mUtilMap[key]
    }
    
    public func mUtilSetValue(_ value:Any?, forKey key: NSDictionary.Key) {
        mUtilMap[key] = value
    }
    
    public subscript<T>(mUtil key: Any) -> T? {
        get { mUtilGetValue(key) }
        set { mUtilSetValue(newValue, forKey: key) }
    }
    
    public func mUtilGetValue<T>(_ key: NSDictionary.Key) -> T? {
        mUtilMap[key] as? T
    }
}

// MARK: - 添加拓展 Dictionary
extension NSObject {

    public var mUtilWeakMap: NSMapTable<NSString, AnyObject> {
        get {
            guard let value = objc_getAssociatedObject(self, &AssociatedKeys.MUtilWeakMap) as? NSMapTable<NSString, AnyObject> else {
                let tMap = NSMapTable<NSString, AnyObject>(keyOptions: .weakMemory, valueOptions: .weakMemory)
                self.mUtilWeakMap = tMap
                return tMap
            }
            return value
        }
        set {
            objc_setAssociatedObject(self,&AssociatedKeys.MUtilWeakMap, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        }
    }
    
    public subscript(mUtilWeak key: NSString) -> AnyObject? {
        get { mUtilWeakGetValue(key) }
        set { mUtilWeakSetValue(newValue, forKey: key) }
    }
    
    public func mUtilWeakGetValue(_ key: NSString) -> AnyObject? {
        mUtilWeakMap.object(forKey: key)
    }
    
    public func mUtilWeakSetValue(_ value:AnyObject?, forKey key: NSString) {
        mUtilWeakMap.setObject(value, forKey: key)
    }
    
    public subscript<T:AnyObject>(mUtilWeak key: NSString) -> T? {
        get { mUtilWeakGetValue(key) }
        set { mUtilWeakSetValue(newValue, forKey: key) }
    }
    
    public func mUtilWeakGetValue<T:AnyObject>(_ key: NSString) -> T? {
        mUtilWeakMap.object(forKey: key) as? T
    }
}

public extension NSObject {
    /// 使用 NSKeyedArchiver 深拷贝一个 UIView（包括 UILabel）
    func deepCopy<T: NSObject>() -> T? {
        do {
            let data = try NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false)
            return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? T
        } catch {
            print("UIView deepCopy failed: \(error)")
            return nil
        }
    }
}

/// var scene2 = Wrapper(content: Scene())    scene2.title = "Scene"
@dynamicMemberLookup
public struct Wrapper<Content> {
    public var content: Content
    
    public init(_ content: Content) {
        self.content = content
    }
    
    public subscript<Value>(dynamicMember keyPath: WritableKeyPath<Content, Value>) -> Value {
        get {
            return content[keyPath: keyPath]
        }
        set {
            content[keyPath: keyPath] = newValue
        }
    }
}

/// Setter(subject: UIView()).frame(CGRect(x: 0, y: 0, width: 100, height: 100)).backgroundColor(.white).object
@dynamicMemberLookup
public class Setter<Subject> {
    
    private var subject: Subject

    public init(_ subject: Subject) {
        self.subject = subject
    }

    public subscript<Value>(dynamicMember keyPath: WritableKeyPath<Subject, Value>) -> (Value) -> Setter<Subject> {
        { value in
            self.subject[keyPath: keyPath] = value
            return self // 返回自身以支持链式调用
        }
    }

    @discardableResult
    public func apply(_ closure: (inout Subject) -> Void) -> Setter<Subject> {
        closure(&subject)
        return self
    }

    @discardableResult
    public func perform(_ closure: (Subject) -> Void) -> Setter<Subject> {
        closure(subject)
        return self
    }
    
    /// 添加一个方法来返回最终的 `object`，支持省略 `.object`
    @discardableResult
    public func build() -> Subject {
        return subject
    }
    
    // 支持直接调用，返回最终 subject
    @discardableResult
    public func callAsFunction() -> Subject {
        return subject
    }

    // 支持直接返回结果
    public var object: Subject { subject }
}

public protocol Settable {}
extension Settable {
    public var setter: Setter<Self> { Setter(self) }
}

extension Settable where Self: NSObject {

    @discardableResult
    public func setter(_ configure: (Setter<Self>) -> Setter<Self>) -> Self {
        let setter = Setter(self)
        _ = configure(setter)
        return setter.object
    }
}

extension NSObject: Settable {}


public struct ZM<Base> {
    public var base: Base
    public init(_ base: Base) {
        self.base = base
    }
}

public protocol ZMCompatible {
    var zm: ZM<Self> {get}
    static var zm: ZM<Self>.Type {get}
}

extension ZMCompatible {
    public var zm: ZM<Self> {
        ZM(self)
    }
    public static var zm: ZM<Self>.Type {
        ZM<Self>.self
    }
}
//extension String: ZMCompatible {}
//extension ZM where Base == String {
//    // 添加方法
//    func test() {
//        print("\(self)::\(self.base)")
//    }
//}
//
func test() {
//    UIView().setter.backgroundColor(.red)
//    "A".zm.test() // ZM<String>(base: "A")::A
}
